﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Afvanding.Properties;
using Afvanding.RefToPumpService;

using System.Collections.ObjectModel;

namespace Afvanding
{
    /// <summary>
    /// GUI til overvågning og styring
    ///Der skal udformes en GUI til overvågning og styring af anlægget. 
    /// Først og fremmest skal man kunne få overblik over pumpestationer. 
    /// Det skal være muligt at udpege en specifik pumpestation og få fremvist detaljer om denne pumpestation.
    /// </summary>
    public partial class MainWindow : Window
    {
        //   readonly ObservableCollection<TestData> _testCollection = new ObservableCollection<TestData>();

        readonly ObservableCollection<Pump> _pumps = new ObservableCollection<Pump>();
        readonly ObservableCollection<Station> _stations = new ObservableCollection<Station>();
        private int _stationId;
        private PumpServiceClient _pumpService;
        private Settings _settings;

        #region Threads
        private Dictionary<int, Log> _logs;
        private Dictionary<int, WaterThread> _waterThreads;
        private Dictionary<int, WaterMonitor> _monitors;
        private Dictionary<int, Thread> _rainThreads;
        private Dictionary<int, Thread> _drainThreads;
        DateTime _date;
        #endregion

        public MainWindow()
        {
            InitializeComponent();

            _stationId = 0;

            _pumpService = new PumpServiceClient();
            lsvStation.ItemsSource = _pumpService.RequestCurrentStatusForAll();
            lsvStation.SelectedIndex = 0;

            _settings = new Settings();
            
            _date = DateTime.Now;
            SimulateThreads(_pumpService);

            Start();
            //Thread.Sleep(10000);
            //Stop();
        }

        public ObservableCollection<Pump> PumpCollection { get { return _pumps; } }
        public ObservableCollection<Station> StationCollection { get { return _stations; } }
        public class TestData
        {
            public string Name { get; set; }
            public string CurrentValue { get; set; }
            public string MinimumValue { get; set; }
            public string MaximumValue { get; set; }
        }

        private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var newStationWindow = new NewStationWindow();
            newStationWindow.Show();
        }

        void DeleteStation_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (lsvStation.SelectedValue != null)
            {
                // Selected station:
                var selectedStationId = ((Station)lsvStation.SelectedValue).Id;

                if (MessageBox.Show("Are you sure that you want to permanently delete this station? Station " + selectedStationId,
                                    "Delete Station",
                                    MessageBoxButton.YesNo,
                                    MessageBoxImage.Warning) == MessageBoxResult.Yes)
                {
                    if (_pumpService.RemoveStation(selectedStationId))
                        _pumpService.RemovePumpsByStationId(selectedStationId);

                    // Update GUI:
                    lsvStation.ItemsSource = null;
                    lsvStation.ItemsSource = _pumpService.RequestCurrentStatusForAll();
                }
            }
            else
                MessageBox.Show("Du skal huske at vælge en station først");
        }

        private void AddPumpBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var selectedStation = (Station)lsvStation.SelectedItem;
            if (selectedStation != null)
            {
                var addPumpWindow = new AddPumpWindow(selectedStation.Id);
                addPumpWindow.Show();
            }
            else
                MessageBox.Show("Du skal vælge en station først");
        }

        private void lsvStation_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                //int stationId = ((Station)lsvStation.SelectedItem).Id;
                _stationId = ((Station)lsvStation.SelectedItem).Id;
                lblStationNr.Content = "Station " + _stationId.ToString();
                lsvPump.ItemsSource = _pumpService.RequestCurrentStatus(_stationId);
            }
            catch (NullReferenceException) { }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            Stop();
        }

        private void OpenProperties_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (lsvStation.SelectedValue != null)
            {
                var selectedStationId = ((Station)lsvStation.SelectedValue).Id;
                var stationPropertiesWindow = new StationPropertiesWindow(selectedStationId);
                stationPropertiesWindow.Show();
            }
            else
                MessageBox.Show("Du skal vælge en station først");
        }

        #region Threads
        private void SimulateThreads(PumpServiceClient service)
        {
            if (_logs == null && _waterThreads == null && _monitors == null && _rainThreads == null && _drainThreads == null)
            {
                _logs = new Dictionary<int, Log>();
                _waterThreads = new Dictionary<int, WaterThread>();
                _monitors = new Dictionary<int, WaterMonitor>();
                _rainThreads = new Dictionary<int, Thread>();
                _drainThreads = new Dictionary<int, Thread>();

                foreach (Station s in _pumpService.RequestCurrentStatusForAll())
                {
                    _logs.Add(s.Id, new Log(s.Id, 0, 0, 0, _date));
                    List<Pump> pumps = _pumpService.RequestCurrentStatus(s.Id);
                    WaterMonitor monitor = new WaterMonitor(s.Id, _date);
                    WaterThread thread = new WaterThread(monitor, pumps, 0, 1000, _settings.RequestFrequency);
                    Thread rain = new Thread(thread.Rain);
                    rain.Name = "rain" + s.Id;
                    _rainThreads.Add(s.Id, rain);

                    foreach (Pump p in _pumpService.RequestCurrentStatus(s.Id))
                    {
                        Thread drain = new Thread(thread.Drain);
                        drain.Name = "drain" + s.Id + "_" + p.Id;
                        _drainThreads.Add(p.Id, drain);
                    }

                    //monitor.LevelValue += LevelHandle;
                    monitor.RainValue += RainHandle;
                    monitor.DrainValue += DrainHandle;

                    _monitors.Add(s.Id, monitor);
                    _waterThreads.Add(s.Id, thread);
                }
            }
        }
        //private void LevelHandle(int id, DateTime date, double value)
        //{
        //    if (_date.AddHours(1).CompareTo(date) == 0) //rain
        //    {
        //        _date = date;
        //        _logs[id].Date = date;
        //        //save to db
        //    }
        //    else { _logs[id].WaterLevel = value; } //drain
        //    System.Diagnostics.Debug.WriteLine("LEVEL - StationId:{0},  Date: {1}, Level: {2}", id, date, value);
        //}

        public void Start()
        {
            foreach (int id in _waterThreads.Keys)
            {
                _waterThreads[id].Start();
                _rainThreads[id].Start();
                _pumpService.StartStation(id);
            }
            foreach (int id in _drainThreads.Keys)
            {
                _drainThreads[id].Start(id);
                _pumpService.StartPump(id); //update in db
            }
        }
        public void StartPump(int pumpId)
        {
            foreach (int id in _waterThreads.Keys) { _waterThreads[id].StartPump(id); }
            _pumpService.StartPump(pumpId);
        }
        public void Pause()
        {
            foreach (int id in _waterThreads.Keys)
            {
                _waterThreads[id].Pause();
                _pumpService.StopStation(id);
            }
        }
        public void PausePump(int pumpId)
        {
            foreach (int id in _waterThreads.Keys) { _waterThreads[id].PausePump(id); }
            _pumpService.StopPump(pumpId); //update in db
        }
        public void Resume()
        {
            foreach (int id in _waterThreads.Keys)
            {
                _waterThreads[id].Resume();
                _pumpService.StartStation(id); //update in db
            }
        }
        public void ResumePump(int pumpId)
        {
            foreach (int id in _waterThreads.Keys) { _waterThreads[id].ResumePump(id); }
            _pumpService.StartPump(pumpId); //update in db
        }
        public void Stop()
        {
            foreach (int id in _waterThreads.Keys)
            {
                _waterThreads[id].Stop();
                _rainThreads[id].Join();
                _rainThreads[id].Abort();
                _pumpService.StopStation(id);
            }
            foreach (int id in _drainThreads.Keys)
            {
                if (_drainThreads[id].ThreadState == ThreadState.Running)
                {
                    _drainThreads[id].Join();
                    _drainThreads[id].Abort();
                    _pumpService.StopPump(id);
                }
            }
        }
        public void StopPump(int pumpId)
        {
            foreach (int id in _waterThreads.Keys) { _waterThreads[id].StopPump(id); }
            _drainThreads[pumpId].Join();
            _pumpService.StopPump(pumpId); //update in db
        }

        private void RainHandle(int id, DateTime date, double value, double level)
        {
            _logs[id].Date = date;
            _logs[id].WaterIn = value;
            _logs[id].WaterLevel = level;

            if (date.CompareTo(_date.AddMinutes(_settings.Save2DbFrequency)) == 0) //new time
            {
                _date = date;
                _pumpService.AddLog(id, value, level, date);
                //save date, waterin, waterlevel to db
            }
            if (_stationId == id)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                    {
                        LblRain.Content = value.ToString();
                        LblLevel.Content = level.ToString();
                    }));
            }
            //System.Diagnostics.Debug.WriteLine("\nRain [{0}]:{1}\nLevel: {2}\nDate: {3}", id, value, level, date);
        }
        private void DrainHandle(int stationId, int pumpId, DateTime date, double value, double level)
        {
            _logs[stationId].Date = date;
            _logs[stationId].WaterOut = value;
            _logs[stationId].WaterLevel = level;

            if (date.CompareTo(_date.AddMinutes(_settings.Save2DbFrequency)) == 0) //new time
            {
                _date = date;
                _pumpService.UpdateLog(stationId, value, level, date);
            }

            if (_stationId == stationId)
            {

                Dispatcher.BeginInvoke(new Action(() =>
                    {
                        LblDrain.Content = value.ToString();
                        LblLevel.Content = level.ToString();
                    }));
            }

            //System.Diagnostics.Debug.WriteLine("\nDrain [{0},{4}]:{1}\nLevel: {2}\nDate: {3}", stationId, value, level, date, pumpId);
        }
        #endregion

        public void UpdatePumpList()
        {
            Dispatcher.BeginInvoke(new Action(() =>
                {
                    var stations = _pumpService.RequestCurrentStatusForAll();
                    foreach (var s in stations)
                    {
                        _pumpService.RequestCurrentStatus(s.Id);
                    }
                }));
        }
    }
}